"""
Excel文件解析器
用于解析包含SQL脚本信息的Excel文件
"""

import pandas as pd
import os
from typing import List, Dict, Any, Tuple
from constants import DatabaseType, ScriptType, ExcelColumns, Messages


class ExcelParser:
    """Excel文件解析器类"""
    
    def __init__(self):
        self.data = None
        self.file_path = None
    
    def get_sheet_names(self, file_path: str) -> Tuple[bool, str, List[str]]:
        """
        获取Excel文件中所有sheet页名称
        
        Args:
            file_path: Excel文件路径
            
        Returns:
            Tuple[bool, str, List[str]]: (成功标志, 消息, sheet页名称列表)
        """
        try:
            # 检查文件是否存在
            if not os.path.exists(file_path):
                return False, Messages.FILE_NOT_FOUND, []
            
            # 获取Excel文件的所有sheet页名称
            excel_file = pd.ExcelFile(file_path)
            sheet_names = excel_file.sheet_names
            excel_file.close()  # 关闭文件句柄
            
            if not sheet_names:
                return False, "Excel文件中没有找到任何sheet页", []
                
            return True, "成功获取sheet页列表", sheet_names
            
        except Exception as e:
            return False, f"读取Excel文件失败: {str(e)}", []
    
    def parse_excel(self, file_path: str, sheet_name: str = None) -> Tuple[bool, str, List[Dict[str, Any]]]:
        """
        解析Excel文件
        
        Args:
            file_path: Excel文件路径
            sheet_name: 指定的sheet页名称，如果为None则使用第一个sheet页
            
        Returns:
            Tuple[bool, str, List[Dict]]: (成功标志, 消息, 解析的数据列表)
        """
        try:
            # 检查文件是否存在
            if not os.path.exists(file_path):
                return False, Messages.FILE_NOT_FOUND, []
            
            # 读取Excel文件
            if sheet_name:
                df = pd.read_excel(file_path, sheet_name=sheet_name)
            else:
                df = pd.read_excel(file_path)
            
            # 验证列格式
            success, message = self._validate_columns(df)
            if not success:
                return False, message, []
            
            # 检查是否有数据
            if df.empty:
                return False, Messages.EMPTY_DATA, []
            
            # 解析数据
            parsed_data = []
            for index, row in df.iterrows():
                # 验证行数据
                validation_result = self._validate_row_data(row, index + 1)
                if not validation_result[0]:
                    return False, validation_result[1], []
                
                # 构建数据字典
                data_item = {
                    'requirement_no': str(row[ExcelColumns.REQUIREMENT_NO]).strip() if pd.notna(row[ExcelColumns.REQUIREMENT_NO]) else '',
                    'database': str(row[ExcelColumns.DATABASE]).strip() if pd.notna(row[ExcelColumns.DATABASE]) else '',
                    'script_type': str(row[ExcelColumns.SCRIPT_TYPE]).strip() if pd.notna(row[ExcelColumns.SCRIPT_TYPE]) else '',
                    'sql_script': str(row[ExcelColumns.SQL_SCRIPT]).strip() if pd.notna(row[ExcelColumns.SQL_SCRIPT]) else '',
                    'remark': str(row[ExcelColumns.REMARK]).strip() if pd.notna(row[ExcelColumns.REMARK]) else '',
                    'rollback_script': str(row[ExcelColumns.ROLLBACK_SCRIPT]).strip() if pd.notna(row[ExcelColumns.ROLLBACK_SCRIPT]) else '',
                    'row_number': index + 1
                }
                
                parsed_data.append(data_item)
            
            self.data = parsed_data
            self.file_path = file_path
            
            return True, Messages.PARSE_SUCCESS, parsed_data
            
        except Exception as e:
            return False, f"{Messages.PARSE_ERROR} {str(e)}", []
    
    def _validate_columns(self, df: pd.DataFrame) -> Tuple[bool, str]:
        """
        验证Excel列格式
        
        Args:
            df: pandas DataFrame
            
        Returns:
            Tuple[bool, str]: (验证成功标志, 错误消息)
        """
        required_columns = ExcelColumns.get_required_columns()
        missing_columns = []
        
        for col in required_columns:
            if col not in df.columns:
                missing_columns.append(col)
        
        if missing_columns:
            return False, f"{Messages.INVALID_FORMAT} {', '.join(missing_columns)}"
        
        return True, ""
    
    def _validate_row_data(self, row: pd.Series, row_number: int) -> Tuple[bool, str]:
        """
        验证行数据
        
        Args:
            row: pandas Series表示的行数据
            row_number: 行号
            
        Returns:
            Tuple[bool, str]: (验证成功标志, 错误消息)
        """
        # 检查必填字段
        requirement_no = str(row[ExcelColumns.REQUIREMENT_NO]).strip() if pd.notna(row[ExcelColumns.REQUIREMENT_NO]) else ''
        database = str(row[ExcelColumns.DATABASE]).strip() if pd.notna(row[ExcelColumns.DATABASE]) else ''
        script_type = str(row[ExcelColumns.SCRIPT_TYPE]).strip() if pd.notna(row[ExcelColumns.SCRIPT_TYPE]) else ''
        sql_script = str(row[ExcelColumns.SQL_SCRIPT]).strip() if pd.notna(row[ExcelColumns.SQL_SCRIPT]) else ''
        
        # 检查空值
        if not requirement_no:
            return False, f"第{row_number}行 - {Messages.EMPTY_REQUIRED_FIELD} {ExcelColumns.REQUIREMENT_NO}"
        
        if not database:
            return False, f"第{row_number}行 - {Messages.EMPTY_REQUIRED_FIELD} {ExcelColumns.DATABASE}"
        
        if not script_type:
            return False, f"第{row_number}行 - {Messages.EMPTY_REQUIRED_FIELD} {ExcelColumns.SCRIPT_TYPE}"
        
        if not sql_script:
            return False, f"第{row_number}行 - {Messages.EMPTY_REQUIRED_FIELD} {ExcelColumns.SQL_SCRIPT}"
        
        # 验证数据库类型
        if not DatabaseType.is_valid(database):
            return False, f"第{row_number}行 - {Messages.INVALID_DATABASE} '{database}', 支持的类型: {', '.join(DatabaseType.get_all())}"
        
        # 验证脚本类型
        if not ScriptType.is_valid(script_type):
            return False, f"第{row_number}行 - {Messages.INVALID_SCRIPT_TYPE} '{script_type}', 支持的类型: {', '.join(ScriptType.get_all())}"
        
        return True, ""
    
    def get_parsed_data(self) -> List[Dict[str, Any]]:
        """获取解析后的数据"""
        return self.data if self.data else []
    
    def get_statistics(self) -> Dict[str, Any]:
        """
        获取数据统计信息
        
        Returns:
            Dict[str, Any]: 统计信息
        """
        if not self.data:
            return {}
        
        stats = {
            'total_records': len(self.data),
            'database_stats': {},
            'script_type_stats': {},
            'has_rollback_count': 0
        }
        
        for item in self.data:
            # 统计数据库类型
            db = item['database']
            stats['database_stats'][db] = stats['database_stats'].get(db, 0) + 1
            
            # 统计脚本类型
            script_type = item['script_type']
            stats['script_type_stats'][script_type] = stats['script_type_stats'].get(script_type, 0) + 1
            
            # 统计有回滚脚本的记录数
            if item['rollback_script']:
                stats['has_rollback_count'] += 1
        
        return stats
    
    def print_data_summary(self) -> None:
        """在控制台打印数据摘要"""
        if not self.data:
            print("没有数据可显示")
            return
        
        print(f"\n=== Excel文件解析结果 ===")
        print(f"文件路径: {self.file_path}")
        print(f"总记录数: {len(self.data)}")
        
        # 获取统计信息
        stats = self.get_statistics()
        
        print(f"\n数据库类型分布:")
        for db_type, count in stats['database_stats'].items():
            print(f"  {db_type}: {count} 条")
        
        print(f"\n脚本类型分布:")
        for script_type, count in stats['script_type_stats'].items():
            print(f"  {script_type}: {count} 条")
        
        print(f"\n包含回滚脚本的记录: {stats['has_rollback_count']} 条")
        
        print(f"\n=== 前5条记录详情 ===")
        for i, item in enumerate(self.data[:5]):
            print(f"\n记录 {i+1}:")
            print(f"  数据库: {item['database']}")
            print(f"  脚本类型: {item['script_type']}")
            print(f"  SQL脚本: {item['sql_script'][:100]}..." if len(item['sql_script']) > 100 else f"  SQL脚本: {item['sql_script']}")
            print(f"  备注: {item['remark']}")
            print(f"  回滚脚本: {item['rollback_script'][:50]}..." if len(item['rollback_script']) > 50 else f"  回滚脚本: {item['rollback_script']}")
        
        if len(self.data) > 5:
            print(f"\n... 还有 {len(self.data) - 5} 条记录")
        
        print("=" * 50)
